use std::{cell::RefCell, rc::Rc, fmt::Display};

pub trait Tree {
    fn new(val: i32) -> Self;
    fn set_child(&mut self, op: u8, child: TreeNode);
    fn get_child(&self, op: u8) -> &Option<Rc<RefCell<TreeNode>>>;
}

#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub l_child: Option<Rc<RefCell<TreeNode>>>,
    pub r_child: Option<Rc<RefCell<TreeNode>>>,
}

impl Tree for TreeNode {
    fn new(val: i32) -> Self {
        return TreeNode {
            val,
            l_child: None,
            r_child: None,
        };
    }
    fn set_child(&mut self, op: u8, child: TreeNode) {
        if op == 0 {
            self.l_child = Some(Rc::new(RefCell::new(child)));
        } else {
            self.r_child = Some(Rc::new(RefCell::new(child)));
        }
    }
    fn get_child(&self, op: u8) -> &Option<Rc<RefCell<TreeNode>>> {
        if op == 0 {
            &self.l_child
        } else {
            &self.r_child
        }
    }
}

impl Display for TreeNode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let l_child_msg = if let Some(c) = &self.l_child {
            format!("A Tree: val: {}", c.borrow().val)
        } else {
            "None".to_string()
        };

        let r_child_msg = if let Some(c) = &self.r_child {
            format!("A Tree: val: {}", c.borrow().val)
        } else {
            "None".to_string()
        };

        write!(
            f,
            "Tree：val: {}, l_child: {}, r_child: {}",
            self.val, l_child_msg, r_child_msg
        )
    }
}
